import { VectorTile } from '@mapbox/vector-tile'
import Pbf from 'pbf'

/**
 * 将瓦片坐标转换为地理坐标
 * @param {number} x - 瓦片内X坐标
 * @param {number} y - 瓦片内Y坐标  
 * @param {number} extent - 瓦片范围 (通常是4096)
 * @param {number} z - 缩放级别
 * @param {number} tileX - 瓦片X坐标
 * @param {number} tileY - 瓦片Y坐标
 * @returns {Object} 包含 lon, lat 的对象
 */
function tileCoordToGeo (x, y, extent, z, tileX, tileY) {
  // 将瓦片内坐标归一化到0-1范围
  const tileRelativeX = x / extent
  const tileRelativeY = y / extent

  // 计算在全球瓦片网格中的绝对位置
  const globalX = tileX + tileRelativeX
  const globalY = tileY + tileRelativeY

  // 转换为经纬度
  const n = Math.pow(2, z)
  const lon = (globalX / n) * 360.0 - 180.0
  const latRad = Math.atan(Math.sinh(Math.PI * (1 - 2 * globalY / n)))
  const lat = latRad * 180.0 / Math.PI

  return { lon, lat }
}

/**
 * 获取瓦片的地理边界
 * @param {number} z - 缩放级别
 * @param {number} x - 瓦片X坐标  
 * @param {number} y - 瓦片Y坐标
 * @returns {Object} 包含边界坐标的对象
 */
function getTileBounds (z, x, y) {
  const n = Math.pow(2, z)
  const lon_deg_west = (x / n) * 360.0 - 180.0
  const lon_deg_east = ((x + 1) / n) * 360.0 - 180.0
  const lat_rad_north = Math.atan(Math.sinh(Math.PI * (1 - 2 * y / n)))
  const lat_rad_south = Math.atan(Math.sinh(Math.PI * (1 - 2 * (y + 1) / n)))
  const lat_deg_north = lat_rad_north * 180.0 / Math.PI
  const lat_deg_south = lat_rad_south * 180.0 / Math.PI

  return {
    west: lon_deg_west,
    south: lat_deg_south,
    east: lon_deg_east,
    north: lat_deg_north
  }
}

/**
 * 异步处理单个图层的要素
 * @param {Object} layer - 图层对象
 * @param {string} layerName - 图层名称
 * @param {number} z - 缩放级别
 * @param {number} x - 瓦片X坐标
 * @param {number} y - 瓦片Y坐标
 * @param {Function} onProgress - 进度回调函数
 * @returns {Promise<Object>} 处理后的图层数据
 */
async function processLayerAsync (layer, layerName, z, x, y, onProgress) {
  const layerData = {
    name: layerName,
    length: layer.length,
    extent: layer.extent,
    version: layer.version,
    features: []
  }

  let pointCount = 0
  let lineCount = 0
  let polygonCount = 0

  const batchSize = 100 // 每批处理100个要素
  const totalFeatures = layer.length

  // 分批处理要素，避免阻塞主线程
  for (let i = 0; i < totalFeatures; i += batchSize) {
    const endIndex = Math.min(i + batchSize, totalFeatures)

    // 处理当前批次
    await new Promise(resolve => {
      // 使用 requestIdleCallback 或 setTimeout 来让出主线程
      const processCallback = (deadline) => {
        const batchStartTime = performance.now()

        for (let j = i; j < endIndex; j++) {
          // 检查是否需要让出主线程
          if (deadline && deadline.timeRemaining() < 1) {
            // 时间不够，延迟到下一个空闲时间
            requestIdleCallback(processCallback)
            return
          }

          // 检查批次处理时间，避免单个批次处理过久
          if (performance.now() - batchStartTime > 16) { // 16ms约为60fps的一帧
            // 延迟到下一个时间片
            setTimeout(() => processCallback(deadline), 0)
            return
          }

          try {
            const feature = layer.feature(j)
            const geometry = feature.loadGeometry()
            const properties = feature.properties
            const type = feature.type // 1=Point, 2=LineString, 3=Polygon

            // 统计几何类型
            if (type === 1) pointCount++
            else if (type === 2) lineCount++
            else if (type === 3) polygonCount++

            // 处理点要素 (我们主要关心POI点)
            if (type === 1 && geometry.length > 0 && geometry[0].length > 0) {
              const point = geometry[0][0]
              const coords = tileCoordToGeo(
                point.x, point.y,
                layer.extent || 4096,
                z, x, y
              )

              layerData.features.push({
                type: type,
                coordinates: [coords.lon, coords.lat],
                properties: properties
              })
            }
            // 处理线要素 (可选)
            else if (type === 2) {
              const coordinates = []
              geometry.forEach(ring => {
                const lineCoords = []
                ring.forEach(point => {
                  const coords = tileCoordToGeo(
                    point.x, point.y,
                    layer.extent || 4096,
                    z, x, y
                  )
                  lineCoords.push([coords.lon, coords.lat])
                })
                coordinates.push(lineCoords)
              })

              // 只保存有名称的线要素
              if (properties.name || properties.name_en || properties.name_zh) {
                layerData.features.push({
                  type: type,
                  coordinates: coordinates,
                  properties: properties
                })
              }
            }
          } catch (error) {
            console.warn(`处理要素 ${j} 时出错:`, error)
          }
        }

        resolve()
      }

      // 优先使用 requestIdleCallback，如果不支持则使用 setTimeout
      if (typeof requestIdleCallback !== 'undefined') {
        requestIdleCallback(processCallback)
      } else {
        setTimeout(() => processCallback(), 0)
      }
    })

    // 报告进度
    if (onProgress) {
      const progress = (endIndex / totalFeatures) * 100
      onProgress(layerName, progress, endIndex, totalFeatures)
    }
  }

  return {
    layerData,
    stats: { pointCount, lineCount, polygonCount }
  }
}

/**
 * 解析矢量瓦片数据（异步版本）
 * @param {ArrayBuffer} buffer - PBF格式的瓦片数据
 * @param {number} z - 缩放级别
 * @param {number} x - 瓦片X坐标
 * @param {number} y - 瓦片Y坐标
 * @param {Function} onProgress - 进度回调函数
 * @returns {Promise<Object>} 解析后的数据对象
 */
export async function parseVectorTile (buffer, z, x, y, onProgress) {
  try {
    console.log('开始异步解析矢量瓦片...')

    const pbf = new Pbf(new Uint8Array(buffer))
    const tile = new VectorTile(pbf)

    const result = {
      z, x, y,
      bounds: getTileBounds(z, x, y),
      layerCount: Object.keys(tile.layers).length,
      totalFeatures: 0,
      layers: [],
      layerDetails: ''
    }

    const layerNames = Object.keys(tile.layers)
    console.log('瓦片包含的图层:', layerNames)

    // 异步处理所有图层
    for (let i = 0; i < layerNames.length; i++) {
      const layerName = layerNames[i]
      const layer = tile.layers[layerName]
      console.log(`开始异步处理图层: ${layerName}, 要素数量: ${layer.length}`)

      // 异步处理单个图层
      const { layerData, stats } = await processLayerAsync(
        layer,
        layerName,
        z, x, y,
        onProgress
      )

      result.layers.push(layerData)
      result.totalFeatures += layerData.features.length

      // 生成图层详情文本
      result.layerDetails += `
        <strong>${layerName}</strong>: ${layer.length}个要素<br/>
        - 点: ${stats.pointCount}, 线: ${stats.lineCount}, 面: ${stats.polygonCount}<br/>
        - 解析出: ${layerData.features.length}个有效要素<br/>
      `

      console.log(`图层 ${layerName} 处理完成，解析出 ${layerData.features.length} 个有效要素`)
    }

    console.log('异步解析完成, 总要素数:', result.totalFeatures)
    return result

  } catch (error) {
    console.error('异步解析矢量瓦片失败:', error)
    throw new Error('异步解析矢量瓦片失败: ' + error.message)
  }
}

/**
 * 格式化要素属性为可读文本
 * @param {Object} properties - 要素属性对象
 * @returns {string} 格式化后的文本
 */
export function formatFeatureProperties (properties) {
  let text = ''
  for (const [key, value] of Object.entries(properties)) {
    if (value !== undefined && value !== null && value !== '') {
      text += `${key}: ${value}\n`
    }
  }
  return text
}

/**
 * 根据要素属性获取显示名称
 * @param {Object} properties - 要素属性
 * @returns {string} 显示名称
 */
export function getFeatureName (properties) {
  return properties.name_zh ||
    properties.name_en ||
    properties.name ||
    properties.class ||
    properties.type ||
    '未命名'
} 